package com.tdrc.common.service;

import com.jcraft.jsch.*;
import com.tdrc.common.core.sftp.SftpProperties;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.util.Properties;

/**
 * @author dpf
 * @version 1.0
 * @date 2020-5-12 15:32
 * @instruction ...
 */
@Service
public class FileService implements IFileService {
    @Resource
    private SftpProperties config;

    private static final Logger logger = LoggerFactory.getLogger(FileService.class);


    /**
     *
     * @param targetDirectory 上传到的文件目录
     * @param targetFileName  上传后的文件名称
     * @param sourceFile  原文件
     */
    @Override
    public void uploadFileBySftp(String targetDirectory, String targetFileName,String sourceFile){
        ChannelSftp sftp = connect();
        try {
            sftp.cd(targetDirectory);
        } catch (SftpException e) {
            try {
                sftp.mkdir(targetDirectory);
                sftp.cd(targetDirectory);
            } catch (SftpException e1) {
                throw new RuntimeException("ftp创建文件路径失败" + targetDirectory);
            }
        }
        File file = new File(sourceFile);
        InputStream inputStream=null;
        try {
            inputStream = new FileInputStream(file);
            sftp.put(inputStream, targetFileName);
        } catch (Exception e) {
            throw new RuntimeException("sftp异常" + e);
        } finally {
            disConnect(sftp);
            closeStream(inputStream,null);
        }
    }

    /**
     *
     * @param sourceDirectory 源文件目录
     * @param sourceFileName  源文件名称
     * @param targetDirectory  下载存储
     * @param targetFileName
     */
    @Override
    public void downloadFileBySftp(String sourceDirectory, String sourceFileName,
                                   String targetDirectory, String targetFileName) {
        OutputStream output = null;
        try {
            File localDirFile = new File(targetDirectory);
            // 判断本地目录是否存在，不存在需要新建各级目录
            if (!localDirFile.exists()) {
                localDirFile.mkdirs();
            }
            if (logger.isInfoEnabled()) {
                logger.info("开始获取远程文件:[{}]---->[{}]", new Object[]{sourceDirectory, targetDirectory});
            }
            ChannelSftp sftp = connect();
             sftp.cd(sourceDirectory);
            if (logger.isInfoEnabled()) {
                logger.info("打开远程文件:[{}]", new Object[]{sourceDirectory});
            }
            output = new FileOutputStream(new File(targetDirectory.concat(File.separator).concat(targetFileName)));
            sftp.get(sourceFileName, output);
            if (logger.isInfoEnabled()) {
                logger.info("文件下载成功");
            }
            disConnect(sftp);
        } catch (Exception e) {
            if (logger.isInfoEnabled()) {
                logger.info("文件下载出现异常，[{}]", e);
            }
            throw new RuntimeException("文件下载出现异常，[{}]", e);
        } finally {
            closeStream(null,output);
        }
    }

    /**
     * 删除文件
     * @param targetDirectory 目标目录
     * @param targetFileName  目标文件名称
     */
    @Override
    public void deleteFileBySftp(String targetDirectory, String targetFileName)  {
        ChannelSftp sftp = null;
        try {
            sftp = this.connect();
            sftp.cd(config.getRoot());
            sftp.rm(targetFileName);
        } catch (Exception e) {
            logger.error("Delete file failure. TargetPath: {}", targetFileName, e);
            e.printStackTrace();
        } finally {
            this.disConnect(sftp);
        }
    }

    /**
     * 连接sftp服务器
     *
     * @return
     */
    public ChannelSftp connect() {
        ChannelSftp sftp = null;
        try {
            JSch jsch = new JSch();
            jsch.getSession(config.getUsername(), config.getHost(), config.getPort());
            Session session = jsch.getSession(config.getUsername(), config.getHost(), config.getPort());
            logger.info("Session created ... UserName=" + config.getUsername() + ";host=" + config.getHost()
                        + ";port=" + config.getPort());
            session.setPassword(config.getPassword());
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            session.setConfig(sshConfig);
            session.connect(config.getSessionConnectTimeout());
            /*sshSession.connect();*/
            logger.info("Session connected ...");
            logger.info("Opening Channel ...");
            Channel channel = session.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;
            logger.info("登录成功");
        } catch (Exception e) {
            logger.error("连接失败！");
        }
        return sftp;
    }
    /**
     * 加密秘钥方式登陆
     * @return
     */
    private ChannelSftp connectByKey() throws Exception {
        JSch jsch = new JSch();
        // 设置密钥和密码 ,支持密钥的方式登陆
        if (StringUtils.isNotBlank(config.getPrivateKey())) {
            if (StringUtils.isNotBlank(config.getPassphrase())) {
                // 设置带口令的密钥
                jsch.addIdentity(config.getPrivateKey(), config.getPassphrase());
            } else {
                // 设置不带口令的密钥
                jsch.addIdentity(config.getPrivateKey());
            }
        }
        logger.info("Try to connect sftp[" + config.getUsername() + "@" + config.getHost() + "], use private key[" + config.getPrivateKey()
                + "] with passphrase[" + config.getPassphrase() + "]");

        Session session = jsch.getSession(config.getUsername(), config.getHost(), config.getPort());
        // 设置登陆超时时间
        session.connect(config.getSessionConnectTimeout());
        logger.info("Session connected to " + config.getHost() + ".");

        // 创建sftp通信通道
        Channel channel = session.openChannel(config.getProtocol());
        channel.connect(config.getChannelConnectedTimeout());
        logger.info("Channel created to " + config.getHost() + ".");
        return (ChannelSftp) channel;
    }
    /**
     * 断掉连接
     */
    public void disConnect(ChannelSftp sftp) {
        try {
            sftp.disconnect();
            sftp.getSession().disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭流
     * @param outputStream
     */
    private void closeStream(InputStream inputStream, OutputStream outputStream) {
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(inputStream != null){
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
